﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Web.Framework;
using Entity.Admin;
using Newtonsoft.Json;
using Core.ZTree;
using Core;

namespace Service
{
    public class MenuService : BaseService<Menu>
    {

        public MenuService(DBEntities db)
            : base(db)
        {

        }

        //public MenuService()
        //    : base()
        //{

        //}

        public override Menu Create(Menu entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity", "entity不能为null");
            }

            if (string.IsNullOrWhiteSpace(entity.ID))
            {
                entity.ID = Guid.NewGuid().ToString();
            }
            ///同级目录下Name不允许一样
            if (db.Menus.Any(p => p.MenuText == entity.MenuText && (p.ParentID == entity.ParentID || string.IsNullOrEmpty(p.ParentID))))
            {
                throw new ModelCheckException("MenuText", "名称不能重复");
            }
            ///同级目录下Oder字段最大的+1
            var maxMenu = db.Menus.Where(p => p.Parent == entity.Parent).OrderByDescending(p => p.OrderIndex).FirstOrDefault();
            if (maxMenu != null)
            {
                entity.OrderIndex = maxMenu.OrderIndex + 1;
            }
            else
            {
                entity.OrderIndex = 1;
            }
            return base.Create(entity);
        }

        public override Menu Save(Menu entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity", "entity不能为null");
            }
            else
            {
                ///同级目录下Name不允许一样
                if (string.IsNullOrEmpty(entity.ParentID))
                {
                    if (db.Menus.Any(p => p.MenuText == entity.MenuText && p.ID != entity.ID && string.IsNullOrEmpty(p.ParentID)))
                    {
                        throw new ModelCheckException("MenuText", "名称不能重复");
                    }
                }
                else
                {
                    if (db.Menus.Any(p => p.MenuText == entity.MenuText && p.ID != entity.ID && p.ParentID == entity.ParentID))
                    {
                        throw new ModelCheckException("MenuText", "名称不能重复");
                    }
                }

            }
            return base.Save(entity);
        }

        public Menu CreateOrSave(Menu entity)
        {
            #region 通用检查
            ///parentId不能是自己或者自己的子集
            if (!string.IsNullOrWhiteSpace(entity.ParentID))
            {
                if (entity.ParentID == entity.ID)
                {
                    throw new ModelCheckException("ParentID", "父菜单不能是自己");
                }
                var menu = db.Menus.Find(entity.ParentID);
                while (menu != null && menu.Parent != null)
                {
                    menu = menu.Parent;
                    if (menu.ID == entity.ParentID)
                    {
                        throw new ModelCheckException("ParentID", "父菜单不能是自己的子菜单");
                    }
                }
            }
            #endregion
            if (db.Menus.Any(p => p.ID == entity.ID))
            {
                return Save(entity);
            }
            else
            {
                return Create(entity);
            }
        }

        public void Delete(string menuId)
        {
            var list = getDeleteList(menuId);
            db.Menus.Where(p => list.Contains(p.ID)).ToList().ForEach(p => { db.Entry(p).State = System.Data.EntityState.Deleted; });
            db.SaveChanges();
        }

        private List<string> getDeleteList(string menuId)
        {
            var list = new List<string>();
            var menu = db.Menus.Find(menuId);
            if (menu != null)
            {
                foreach (var item in menu.Children)
                {
                    list.AddRange(getDeleteList(item.ID));
                }
                list.Add(menu.ID);
            }
            return list;
        }

        /// <summary>
        /// 菜单树
        /// </summary>
        /// <param name="parentId">父菜单ID</param>
        /// <returns></returns>
        public List<TreeNode> TreeNode(string parentId)
        {
            List<TreeNode> treeNodes = new List<TreeNode>();
            var list2 = GetMenuByParentId(parentId);
            foreach (var item in list2)
            {
                TreeNode treeNode = new TreeNode()
                {
                    ID = item.ID,
                    Name = item.MenuText,
                    Children = TreeNode(item.ID),
                    Object = new { item.Area, item.Controller, item.Action }
                };
                treeNodes.Add(treeNode);
            }
            return treeNodes;
        }

        public string GetMenusJson(string parentId)
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(TreeNode(parentId));
        }


        public List<TreeNode> TreeNode(string parentId, bool menuEnable)
        {
            List<TreeNode> treeNodes = new List<TreeNode>();
            var list2 = GetMenuByParentId(parentId, menuEnable);
            foreach (var item in list2)
            {
                TreeNode treeNode = new TreeNode();
                treeNode.ID = item.ID;
                treeNode.Name = item.MenuText;
                treeNode.Children = new List<TreeNode>();
                treeNode.Object = new { item.Area, item.Controller, item.Action };
                treeNode.Children.AddRange(TreeNode(item.ID, menuEnable));
                treeNodes.Add(treeNode);
            }
            return treeNodes;
        }

        public List<TreeNode> TreeNode(string parentId, bool menuEnable, IEnumerable<string> checkedId)
        {
            List<TreeNode> treeNodes = new List<TreeNode>();
            var list2 = GetMenuByParentId(parentId, menuEnable);
            foreach (var item in list2)
            {
                TreeNode treeNode = new TreeNode();
                treeNode.ID = item.ID;
                treeNode.Name = item.MenuText;
                treeNode.Children = new List<TreeNode>();
                treeNode.Object = new { item.Area, item.Controller, item.Action };
                treeNode.Checked = checkedId.Contains(item.ID);
                treeNode.Children.AddRange(TreeNode(item.ID, menuEnable, checkedId));
                treeNodes.Add(treeNode);
            }
            return treeNodes;
        }

        public List<TreeNode> TreeNode(string parentId, IEnumerable<string> checkedId)
        {
            List<TreeNode> treeNodes = new List<TreeNode>();
            var list2 = GetMenuByParentId(parentId);
            foreach (var item in list2)
            {
                TreeNode treeNode = new TreeNode();
                treeNode.ID = item.ID;
                treeNode.Name = item.MenuText;
                treeNode.Object = new { item.Area, item.Controller, item.Action };
                treeNode.Checked = checkedId.Contains(item.ID);
                treeNode.Children.AddRange(TreeNode(item.ID, checkedId));
                treeNodes.Add(treeNode);
            }
            return treeNodes;
        }



        /// <summary>
        /// 根据ParentId取菜单
        /// </summary>
        /// <param name="parentId"></param>
        /// <returns></returns>
        public List<Menu> GetMenuByParentId(string parentId)
        {
            IEnumerable<Menu> menus = new List<Menu>();
            if (string.IsNullOrWhiteSpace(parentId))
            {
                menus = db.Menus.Where(a => string.IsNullOrEmpty(a.ParentID));
            }
            else
            {
                menus = db.Menus.Where(a => a.ParentID == parentId);
            }
            return menus.OrderBy(p => p.OrderIndex).ToList();
        }
        /// <summary>
        /// 获取某菜单的下一级所有子菜单
        /// </summary>
        /// <param name="parentId">父菜单ID</param>
        /// <param name="menuEnable">菜单是否启用</param>
        /// <returns></returns>
        public List<Menu> GetMenuByParentId(string parentId, bool menuEnable)
        {
            IEnumerable<Menu> menus = new List<Menu>();
            if (string.IsNullOrWhiteSpace(parentId))
            {
                menus = db.Menus.Where(a => string.IsNullOrEmpty(a.ParentID) && a.Enable == menuEnable);
            }
            else
            {
                menus = db.Menus.Where(a => a.ParentID == parentId && a.Enable == menuEnable);
            }
            return menus.OrderBy(p => p.OrderIndex).ToList();
        }

        public static List<Menu> ToDropDownList(string parentId)
        {
            var list = new List<Menu>();
            var parentMenus = new List<Menu>();
            DBEntities db = new DBEntities();
            if (string.IsNullOrWhiteSpace(parentId))
            {
                parentMenus = db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID)).OrderBy(p => p.OrderIndex).ToList();
            }
            else
            {
                parentMenus = db.Menus.Where(p => p.ParentID == parentId).OrderBy(p => p.OrderIndex).ToList();
            }
            foreach (var item in parentMenus)
            {
                item.MenuText = item.MenuText.PadLeft(item.Layer * 3 + item.MenuText.Length, '-');
                //item.MenuText = "|" + item.MenuText;
                list.Add(item);
                while (item.Children.Count > 0)
                {
                    list.AddRange(ToDropDownList(item.ID));
                    break;
                }
            }
            return list;
        }

        public void MoveTo(string id, string targetId, TreeNodeMoveType type)
        {
            var moveMenu = db.Menus.Find(id);
            var moveTargetMenu = db.Menus.Find(targetId);
            //moveTargetMenu ==null 说明目标节点是父目录,或者传过来一个数据库中不存在的ID
            ///moveMenu 新的orderIndex
            int orderIndex = 0;
            Nullable<int> maxOrder;
            switch (type)
            {
                #region Prev
                case TreeNodeMoveType.Prev:
                    ///移动到某一节点的上面==移动到某一节点上面一个节点的下面
                    moveMenu.ParentID = moveTargetMenu == null ? null : moveTargetMenu.ParentID;
                    var tempMenu = new Menu();
                    #region 目标节点不存在
                    if (moveTargetMenu == null)
                    {
                        orderIndex = 1;
                        moveMenu.OrderIndex = orderIndex;
                        db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID) && p.OrderIndex >= orderIndex && p.ID != moveMenu.ID).OrderBy(p => p.OrderIndex).ToList().ForEach(p =>
                            {
                                p.OrderIndex = ++orderIndex;
                            }
                        );
                    }
                    #endregion
                    #region 目标节点存在
                    else
                    {
                        #region 目标节点为顶级节点
                        if (moveTargetMenu.ParentID == null)
                        {
                            tempMenu = db.Menus.Where(p => p.OrderIndex < moveTargetMenu.OrderIndex && string.IsNullOrEmpty(p.ParentID)).OrderByDescending(p => p.OrderIndex).FirstOrDefault();
                            orderIndex = tempMenu == null ? 1 : tempMenu.OrderIndex.HasValue ? tempMenu.OrderIndex.Value + 1 : 1;
                            moveMenu.OrderIndex = orderIndex;
                            db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID) && p.OrderIndex >= orderIndex && p.ID != moveMenu.ID).OrderBy(p => p.OrderIndex).ToList().ForEach(p =>
                            {
                                p.OrderIndex = ++orderIndex;
                            }
                            );
                        }
                        #endregion
                        #region 目标节点为叶子
                        else
                        {
                            tempMenu = db.Menus.Where(p => p.OrderIndex < moveTargetMenu.OrderIndex && p.ParentID == moveTargetMenu.ParentID).OrderByDescending(p => p.OrderIndex).FirstOrDefault();
                            orderIndex = tempMenu == null ? 1 : tempMenu.OrderIndex.HasValue ? tempMenu.OrderIndex.Value + 1 : 1;
                            moveMenu.OrderIndex = orderIndex;
                            db.Menus.Where(p => p.ParentID == moveTargetMenu.ParentID && p.OrderIndex >= orderIndex && p.ID != moveMenu.ID).OrderBy(p => p.OrderIndex).ToList().ForEach(p =>
                            {
                                p.OrderIndex = ++orderIndex;
                            }
                            );
                        }
                        #endregion
                    }
                    #endregion
                #endregion
                    break;
                #region Inner
                case TreeNodeMoveType.Inner:
                    if (moveTargetMenu == null)
                    {
                        maxOrder = db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID)).Max(p => p.OrderIndex);
                    }
                    else
                    {
                        maxOrder = db.Menus.Where(p => p.ParentID == moveTargetMenu.ID).Max(p => p.OrderIndex);
                    }
                    moveMenu.ParentID = moveTargetMenu == null ? null : moveTargetMenu.ID;
                    orderIndex = maxOrder.HasValue ? maxOrder.Value + 1 : 1;
                    moveMenu.OrderIndex = orderIndex;
                #endregion
                    break;
                #region Next
                case TreeNodeMoveType.Next:
                    moveMenu.ParentID = moveTargetMenu == null ? null : moveTargetMenu.ParentID;
                    #region 目标节点不存在
                    if (moveTargetMenu == null)
                    {
                        maxOrder = db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID)).Max(p => p.OrderIndex);
                        orderIndex = maxOrder.HasValue ? maxOrder.Value + 1 : 1;
                        moveMenu.OrderIndex = orderIndex;
                        db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID) && p.OrderIndex >= orderIndex && p.ID != moveMenu.ID).OrderBy(p => p.OrderIndex).ToList().ForEach(p =>
                            {
                                p.OrderIndex = ++orderIndex;
                            }
                        );
                    }
                    #endregion
                    #region 目标节点存在
                    else
                    {
                        #region 目标节点为顶级节点
                        if (moveTargetMenu.ParentID == null)
                        {
                            maxOrder = db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID)).Max(p => p.OrderIndex);
                            orderIndex = maxOrder.HasValue ? maxOrder.Value + 1 : 1;
                            moveMenu.OrderIndex = orderIndex;
                            db.Menus.Where(p => string.IsNullOrEmpty(p.ParentID) && p.OrderIndex >= orderIndex && p.ID != moveMenu.ID).OrderBy(p => p.OrderIndex).ToList().ForEach(p =>
                            {
                                p.OrderIndex = ++orderIndex;
                            }
);
                        }
                        #endregion
                        #region 目标节点为叶子
                        else
                        {
                            db.Menus.Where(p => p.ParentID == moveTargetMenu.ParentID && p.OrderIndex >= orderIndex && p.ID != moveMenu.ID).OrderBy(p => p.OrderIndex).ToList().ForEach(p =>
                            {
                                p.OrderIndex = ++orderIndex;
                            }
    );
                        }
                        #endregion
                    }
                    #endregion
                #endregion
                    break;
                default:
                    break;
            }
            db.SaveChanges();
        }

        /// <summary>
        /// 获取导航栏标题集
        /// </summary>
        /// <param name="MenuID">当前菜单ID</param>
        /// <returns></returns>
        public List<string> GetNavbarNames(string menuID)
        {
            List<string> lst = new List<string>();
            if (!string.IsNullOrEmpty(menuID))
            {
                Menu menu = db.Menus.Find(menuID);
                while (!string.IsNullOrEmpty(menu.ParentID))
                {
                    lst.Insert(0, menu.MenuText);
                    menu = db.Menus.Find(menu.ParentID);
                }
                if (string.IsNullOrEmpty(menu.ParentID))
                {
                    lst.Insert(0, menu.MenuText);
                }
            }
            return lst;
        }
    }
}
